package com.qudian.pay.schedule.service;

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.qudian.pay.schedule.enums.ConsoleEnum;
import com.qudian.pay.schedule.enums.StrategyTypeEnum;
import com.qudian.pay.schedule.model.ScheduleDistribution;
import com.qudian.pay.schedule.model.TaskModel;
import com.qudian.pay.schedule.redis.JedisTool;
import com.qudian.pay.schedule.util.Constant;

public class MonitorService {
	
	private static Logger logger = LoggerFactory.getLogger(MonitorService.class);
	
	@Autowired
	private IScheduleService scheduleService;
	
	@Autowired
	private JedisTool jedisTool;
	
	private int init = 0;
	
	private static String serviceUUID;
	
	private volatile boolean shutdownFlag;
	
	private Executor backMonitorThreadExecutor = Executors.newSingleThreadExecutor();
	
	private Executor backgroundClearThreadExecutor = Executors.newSingleThreadExecutor();
	
	public static String getServiceUUID() {
		return serviceUUID;
	}
	
	public void init() {
		shutdownFlag = false;
		serviceUUID = UUID.randomUUID().toString();
		if (StringUtils.isBlank(jedisTool.getValue(ConsoleEnum.SCHEDULE_TYPE.getCode()))) {
			jedisTool.setValue(ConsoleEnum.SCHEDULE_TYPE.getCode(), StrategyTypeEnum.FREE_ORDER.toString());
		}
		ownServiceTag(serviceUUID);
		this.backMonitorThreadExecutor.execute(new BackMonitorThread(serviceUUID));
		this.backgroundClearThreadExecutor.execute(new BackgroundClearThread());
	}
	
	/**
	 * @Description: 关闭的时候销毁线程
	 * @return void 返回类型
	 * @author gaoxiang
	 * @date 2016年5月19日 下午1:04:56
	 */
	public void destroy() {
		shutdownFlag = true;
	}
	
	private boolean ownServiceTag(String serviceUUID) {
		String cacheServiceUUID = jedisTool.getValue(ConsoleEnum.UUID_KEY.getCode());
		if (StringUtils.isBlank(cacheServiceUUID)) {
			jedisTool.setValue(ConsoleEnum.UUID_KEY.getCode(), serviceUUID);
			jedisTool.expire(ConsoleEnum.UUID_KEY.getCode(), 10);
		} else if (cacheServiceUUID.equals(serviceUUID)) {
			jedisTool.expire(ConsoleEnum.UUID_KEY.getCode(), 10);
		} else if (!cacheServiceUUID.equals(serviceUUID)) {
			return false;
		}
		return true;
	}
	
	class BackgroundClearThread implements Runnable {
		
		@Override
		public void run() {
			logger.debug("后台客户端结点清理线程。。。。");
			while (!shutdownFlag)
				try {
					Thread.sleep(5000L);
					long expireServerTime = jedisTool.ttl(ConsoleEnum.UUID_KEY.getCode());
					if (expireServerTime == -1L) {
						jedisTool.del(ConsoleEnum.UUID_KEY.getCode());
					}
					Set<String> keys = jedisTool.keys(Constant.SCHEMA_KEY + "*");
					if (keys != null) {
						Iterator<String> ite = keys.iterator();
						if (ite.hasNext()) {
							String key = ite.next();
							long expireTime = jedisTool.ttl(key);
							if (expireTime == -1L) {
								jedisTool.del(key);
							}
							continue;
						}
					}
				} catch (Throwable e) {
					logger.error("后台清理线程异常", e);
				}
		}
	}
	
	class BackMonitorThread implements Runnable {
		
		private String serviceUUID;
		
		public BackMonitorThread(String serviceUUID) {
			this.serviceUUID = serviceUUID;
		}
		
		public void run() {
			logger.info("后台客户端结点监控开始。。。。");
			boolean changeAble = false;
			logger.info(shutdownFlag + "注册结点发生了变化！");
			while (!shutdownFlag)
				try {
					if (!ownServiceTag(this.serviceUUID)) {
						Thread.sleep(5000L);
					} else {
						String mark = jedisTool.getValue("NODE_CHANGE_MARK");
						List<TaskModel> taskModels = scheduleService.queryTaskModelsWithExp();
						if (taskModels.isEmpty()) {
							scheduleService.stopSchedule();
							jedisTool.del("NODE_CHANGE_MARK");
						} else {
							String newHashSum = scheduleService.getHashSum(taskModels);
							changeAble = !newHashSum.equals(mark);
							if ((changeAble) || (init == 0)) {
								init();
								logger.info("注册结点发生了变化！");
								String scheduleType = jedisTool.getValue(ConsoleEnum.SCHEDULE_TYPE.getCode());
								if (StringUtils.isNotBlank(scheduleType)) {
									StrategyTypeEnum strategyType = StrategyTypeEnum.valueOf(scheduleType);
									ScheduleDistribution distribution = scheduleService.createDistribution(strategyType);
									scheduleService.startSchedule(distribution);
								}
								changeAble = false;
								Thread.sleep(5000L);
							}
						}
					}
				} catch (Throwable t) {
					logger.error("MonitorService exception", t);
				}
		}
	}
}
